import numpy as np
import math as m

class VIKOR:
    def __init__(self, DecisionMatrix, weight, q):
        '''
        假设只有效益型
        :param DecisionMatrix: 决策矩阵
        :param wight: 属性权重
        :param q: q值
        '''
        self.matrix = DecisionMatrix
        self.weight = weight
        self.q = q

    def addition(self,Ivq1,Ivq2,q):
        '''
        加法
        :param Ivq1:区间值
        :param Ivq2:区间值
        :param q:q值
        :return:
        '''
        a,b,c,d=Ivq1[0][0],Ivq1[0][1],Ivq1[1][0],Ivq1[1][1]
        e,f,g,h=Ivq2[0][0],Ivq2[0][1],Ivq2[1][0],Ivq2[1][1]
        u1=a**q+e**q-(a**q)*(e**q)
        u2=b**q+f**q-(b**q)*(f**q)
        v1=c*g
        v2=h*d
        return ([u1,u2],[v1,v2])

    def subtraction(self,Ivq1,Ivq2,q):
        '''
        减法
        :param Ivq1:区间值
        :param Ivq2:区间值
        :param q:q值
        :return:
        '''
        a,b,c,d=Ivq1[0][0],Ivq1[0][1],Ivq1[1][0],Ivq1[1][1]
        e,f,g,h=Ivq2[0][0],Ivq2[0][1],Ivq2[1][0],Ivq2[1][1]
        u1=a*g
        u2=b*h
        v1=(c**q+e**q-(c**q)*(e**q))**(1/q)
        v2=(d**q+f**q-(d**q)*(f**q))**(1/q)
        return ([u1, u2],[v1, v2])

    def multiplication(self,Ivq1,Ivq2,q):
        '''
        乘法
        :param Ivq1:区间值
        :param Ivq2:区间值
        :param q:q值
        :return:
        '''
        a, b, c, d = Ivq1[0][0], Ivq1[0][1], Ivq1[1][0], Ivq1[1][1]
        e, f, g, h = Ivq2[0][0], Ivq2[0][1], Ivq2[1][0], Ivq2[1][1]
        u1 = a * e
        u2 = b * f
        v1 = (c ** q + g ** q - (c ** q) * (g ** q)) ** (1 / q)
        v2 = (d ** q + h ** q - (d ** q) * (h ** q)) ** (1 / q)
        return ([u1, u2], [v1, v2])

    def division(self,Ivq1,Ivq2,q):
        '''
        除法
        :param Ivq1:区间值
        :param Ivq2:区间值
        :param q:q值
        :return:
        '''
        a, b, c, d = Ivq1[0][0], Ivq1[0][1], Ivq1[1][0], Ivq1[1][1]
        e, f, g, h = Ivq2[0][0], Ivq2[0][1], Ivq2[1][0], Ivq2[1][1]
        u1 = (a ** q + g ** q - (a ** q) * (g ** q)) ** (1 / q)
        u2 = (b ** q + h ** q - (b ** q) * (h ** q)) ** (1 / q)
        v1 = c*e
        v2 = d*f
        return ([u1, u2], [v1, v2])

    def getscore(self,IVq):
        '''
        我们提出的得分函数
        :param IVq:区间值
        :param q:q值
        :return:
        '''
        a = IVq[0][0]
        b = IVq[0][1]
        c = IVq[1][0]
        d = IVq[1][1]
        return (m.log(a + b + c + d + 1)+ 2*(a - c + b - d)+((b - a) + (d - c)) +(c + b - a - d)-np.sign(a+b+c+d) * (m.log(3)))/4

    def Exponentiation(self,Ivq1,q,n):
        '''
        次方运算
        :param Ivq1:
        :param q:
        :param n:开多少次方
        :return:
        '''
        a, b, c, d = Ivq1[0][0], Ivq1[0][1], Ivq1[1][0], Ivq1[1][1]
        u1 = a ** n
        u2 = b ** n
        v1 =(1-((1-(c**q))**n))**(1/q)
        v2 =(1-((1-(d**q))**n))**(1/q)
        return ([u1, u2], [v1, v2])

    def PositiveCostIndex(self,Matrix,q):
        '''
        将成本型指标正向化(一般用不着)
        :param DecisionMatrix:
        :return:
        '''
        n=-1#成本型指标元素取倒数
        costindex=(1,4)#表示哪一列是成本型指标
        for i in range(len(Matrix)):
            for j in costindex:
                Matrix[i][j]=self.Exponentiation(Matrix[i][j],q,n)
        return Matrix

    def NormalizedMatrix(self,Matrix,q):
        '''
        规范化矩阵
        :param Matrix:决策矩阵
        :param q:q值
        :return:Matrix规范化之后的矩阵
        '''
        for i in range(len(Matrix)):
            for j in range(len(Matrix[0])):
                a0=self.multiplication(Matrix[i][j],Matrix[i][j],q)
                for k in range(1,len(Matrix)):
                    a1=Matrix[i][k]
                    a0=self.addition(a0,self.multiplication(a1,a1,q),q)
                a0=self.Exponentiation(a0,q,0.5)
                Matrix[i][j]=self.division(Matrix[i][j],a0,q)
        return Matrix

    def getPosNegPoint(self, NormalizedMatrix):
        '''
        求正负理想解
        :param NormalizedMatrix: 区间值矩阵
        :param q: q值
        :return: 传入区间值矩阵的贴近度矩阵
        '''
        Row, Column = len(NormalizedMatrix), len(NormalizedMatrix[0])
        for i in range(Row):
            Positiveline, Negativeline = [], []
            for j in range(Column):
                ##求理想点
                Positiveidu1 = np.max((((NormalizedMatrix[:, j])[:, 0])[:, 0]))
                Positiveidu2 = np.max((((NormalizedMatrix[:, j])[:, 0])[:, 1]))
                Positiveidv1 = np.min((((NormalizedMatrix[:, j])[:, 1])[:, 0]))
                Positiveidv2 = np.min((((NormalizedMatrix[:, j])[:, 1])[:, 1]))
                Negativeidu1 = np.min((((NormalizedMatrix[:, j])[:, 0])[:, 0]))
                Negativeidu2 = np.min((((NormalizedMatrix[:, j])[:, 0])[:, 1]))
                Negativeidv1 = np.max((((NormalizedMatrix[:, j])[:, 1])[:, 0]))
                Negativeidv2 = np.max((((NormalizedMatrix[:, j])[:, 1])[:, 1]))
                Positiveline.append(([Positiveidu1, Positiveidu2], [Positiveidv1, Positiveidv2]))
                Negativeline.append(([Negativeidu1, Negativeidu2], [Negativeidv1, Negativeidv2]))

        return Positiveline, Negativeline

    def getSi(self, NormalizedMatrix, Positiveline, Negativeline, weight, q):
        '''
        求解Si
        :param NormalizedMatrix:规范化矩阵
        :param Positiveline: 正理想解
        :param Negativeline: 负理想解
        :param weight:权重
        :param q:q值
        :return:Si
        '''
        Si=[]
        for i in range(len(NormalizedMatrix)):
            s0=0
            for j in range(len(NormalizedMatrix[0])):
                molecular=self.subtraction(Positiveline[j], NormalizedMatrix[i][j], q)
                denominator=self.subtraction(Positiveline[j], Negativeline[j], q)
                Ivq=self.division(molecular, denominator, q)
                s0+=weight[j]*(self.getscore(Ivq))
            Si.append(s0)
        return Si


    def getRi(self, NormalizedMatrix, Positiveline, Negativeline, weight, q):
        '''
        求解Ri
        :param NormalizedMatrix: 规范化矩阵
        :param Positiveline: 正理想解
        :param Negativeline: 负理想解
        :param weight:权重
        :param q:q值
        :return:Ri
        '''
        Ri = []
        for i in range(len(NormalizedMatrix)):
            s0 = []
            for j in range(len(NormalizedMatrix[0])):
                molecular = self.subtraction(Positiveline[j], NormalizedMatrix[i][j], q)
                denominator = self.subtraction(Positiveline[j], Negativeline[j], q)
                Ivq = self.division(molecular, denominator, q)
                s0.append(weight[j] * self.getscore(Ivq))
            Ri.append(max(s0))
        return Ri

    def getQi(self,Si,Ri):
        '''

        :param Si:
        :param Ri:
        :return:
        '''
        v=0.5#参数
        Smax,Smin,Rmax,Rmin=max(Si),min(Si),max(Ri),min(Ri)
        Qi=[]
        for i in range(len(Si)):
            Q=v*((Si[i]-Smin)/(Smax-Smin))+(1-v)*((Ri[i]-Rmin)/(Rmax-Rmin))
            Qi.append(Q)
        return Qi


    def getResult(self):
        '''

        :param Matrix:
        :param q:
        :return:
        '''
        NormalizedMatrix=self.NormalizedMatrix(self.matrix,self.q)
        Positiveline, Negativeline= self.getPosNegPoint(NormalizedMatrix)
        # print(f'Positiveline形状:{np.shape(Positiveline)}')
        Si,Ri=self.getSi(NormalizedMatrix, Positiveline, Negativeline, self.weight, self.q),self.getRi(NormalizedMatrix, Positiveline, Negativeline, self.weight, self.q)
        Qi = self.getQi(Si, Ri)
        Qi=[i/sum(Qi) for i in Qi]
        return Qi



if __name__ == "__main__":
    Matrix = np.array([[([0.58, 0.75], [0.1, 0.2]), ([0.7, 0.78], [0.2, 0.3]), ([0.5, 0.78], [0.1, 0.2]),
                        ([0.65, 0.7], [0.3, 0.35]), ([0.4, 0.5], [0.5, 0.6])],
                       [([0.5, 0.6], [0.1, 0.2]), ([0.75, 0.78], [0.2, 0.3]), ([0.6, 0.78], [0.1, 0.15]),
               ([0.7, 0.8], [0.2, 0.3]), ([0.5, 0.6], [0.4, 0.5])],
                       [([0.5, 0.78], [0.1, 0.2]), ([0.6, 0.7], [0.3, 0.4]), ([0.7, 0.78], [0.2, 0.3]), ([0.6, 0.7], [0.3, 0.4]),
               ([0.35, 0.45], [0.5, 0.65])],
                       [([0.75, 0.780], [0.2, 0.3]), ([0.6, 0.75], [0.2, 0.3]), ([0.7, 0.78], [0.2, 0.3]),
               ([0.55, 0.65], [0.3, 0.4]), ([0.35, 0.4], [0.6, 0.65])],
                       [([0.6, 0.75], [0.3, 0.4]), ([0.5, 0.6], [0.4, 0.5]), ([0.6, 0.7], [0.3, 0.4]), ([0.5, 0.6], [0.4, 0.5]),
               ([0.1, 0.2], [0.4, 0.5])]])
    weight = (0.2, 0.2, 0.2, 0.2, 0.2)

    vikor = VIKOR(Matrix, weight, 3)

    result = vikor.getResult()
    print(f'Qi={np.round(result,4)}')

